package commands

import (
	"encoding/json"
	"fmt"
	"os"
	"strings"
	"text/tabwriter"

	"github.com/spf13/cobra"
	client "github.com/yourusername/lvm-manager/pkg/client"
)

// DomainCommands returns a command object for domain management
// It does NOT take a client; instead, each subcommand creates its own client using the --api flag.
func DomainCommands() *cobra.Command {
	cmd := &cobra.Command{
		Use:     "domain",
		Short:   "Manage domains (virtual machines)",
		Aliases: []string{"vm", "d"},
	}

	cmd.AddCommand(
		domainListCmd(),
		domainGetCmd(),
		domainCreateCmd(),
		domainStartCmd(),
		domainStopCmd(),
		domainDestroyCmd(),
		domainRebootCmd(),
		domainDeleteCmd(),
	)

	return cmd
}

// domainListCmd lists all domains
func domainListCmd() *cobra.Command {
	var includeInactive bool

	cmd := &cobra.Command{
		Use:     "list",
		Short:   "List all domains",
		Aliases: []string{"ls"},
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(cmd)
			domains, err := apiClient.ListDomains(includeInactive)
			if err != nil {
				return fmt.Errorf("failed to list domains: %w", err)
			}

			w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
			fmt.Fprintln(w, "NAME\tSTATE\tCPUs\tMEMORY(MB)\tAUTOSTART\tPERSISTENT\tIPV4 ADDRS")
			fmt.Fprintln(w, "----\t-----\t----\t----------\t---------\t----------\t----------")

			for _, d := range domains {
				autostart := "no"
				if d.Autostart {
					autostart = "yes"
				}
				persistent := "no"
				if d.Persistent {
					persistent = "yes"
				}

				ipv4Addrs := "N/A"
				if len(d.Ipv4Addrs) > 0 {
					ipv4Addrs = strings.Join(d.Ipv4Addrs, ", ")
				}

				fmt.Fprintf(w, "%s\t%s\t%d\t%d\t%s\t%s\t%s\n",
					d.Name, d.State, d.CPUs, d.Memory/1024, autostart, persistent, ipv4Addrs)
			}
			w.Flush()

			fmt.Printf("\nTotal: %d domains\n", len(domains))
			return nil
		},
	}

	cmd.Flags().BoolVarP(&includeInactive, "all", "", false, "Include inactive domains")
	return cmd
}

// domainGetCmd gets domain details
func domainGetCmd() *cobra.Command {
	var outputJSON bool
	var includeXML bool

	cmd := &cobra.Command{
		Use:   "get <name>",
		Short: "Get domain details",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(cmd)
			name := args[0]
			domain, err := apiClient.GetDomain(name, includeXML)
			if err != nil {
				return fmt.Errorf("failed to get domain: %w", err)
			}

			if outputJSON {
				data, _ := json.MarshalIndent(domain, "", "  ")
				fmt.Println(string(data))
			} else {
				fmt.Printf("Name:        %s\n", domain.Name)
				fmt.Printf("UUID:        %s\n", domain.UUID)
				fmt.Printf("State:       %s\n", domain.State)
				fmt.Printf("CPUs:        %d\n", domain.CPUs)
				fmt.Printf("Memory:      %d MB\n", domain.Memory/1024)
				fmt.Printf("Max Memory:  %d MB\n", domain.MaxMemory/1024)
				fmt.Printf("Autostart:   %v\n", domain.Autostart)
				fmt.Printf("Persistent:  %v\n", domain.Persistent)
				fmt.Printf("IPv4 Addrs:  %v\n", domain.Ipv4Addrs)

				if includeXML && domain.XMLConfig != "" {
					fmt.Printf("\nXML Configuration:\n%s\n", domain.XMLConfig)
				}
			}
			return nil
		},
	}

	cmd.Flags().BoolVarP(&outputJSON, "json", "j", false, "Output in JSON format")
	cmd.Flags().BoolVarP(&includeXML, "xml", "x", false, "Include XML configuration")
	return cmd
}

// domainCreateCmd creates a new domain
func domainCreateCmd() *cobra.Command {
	var spec client.CreateSpec

	cmd := &cobra.Command{
		Use:   "create",
		Short: "Create a new domain",
		RunE: func(cmd *cobra.Command, args []string) error {
			if spec.Name == "" {
				return fmt.Errorf("name is required")
			}
			if spec.DiskPath == "" {
				return fmt.Errorf("disk path is required")
			}
			apiClient := getAPIClient(cmd)

			domain, err := apiClient.CreateDomain(&spec)
			if err != nil {
				return fmt.Errorf("failed to create domain: %w", err)
			}

			fmt.Printf("Domain '%s' created successfully (UUID: %s)\n", domain.Name, domain.UUID)
			fmt.Printf("State: %s\n", domain.State)
			return nil
		},
	}

	cmd.Flags().StringVar(&spec.Name, "name", "", "Domain name (required)")
	cmd.Flags().UintVar(&spec.Memory, "memory", 1024, "Memory in MB")
	cmd.Flags().UintVar(&spec.VCPUs, "vcpus", 1, "Number of virtual CPUs")
	cmd.Flags().StringVar(&spec.DiskPath, "disk", "", "Disk image path (required)")
	cmd.Flags().StringVar(&spec.NetworkType, "network-type", "network", "Network type: bridge, network, user")
	cmd.Flags().StringVar(&spec.NetworkName, "network-name", "default", "Network or bridge name")

	cmd.MarkFlagRequired("name")
	cmd.MarkFlagRequired("disk")

	return cmd
}

// domainStartCmd starts a domain
func domainStartCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "start <name>",
		Short: "Start a domain",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(cmd)

			if err := apiClient.DomainAction(args[0], "start"); err != nil {
				return fmt.Errorf("failed to start domain: %w", err)
			}
			fmt.Printf("Domain '%s' started\n", args[0])
			return nil
		},
	}
}

// domainStopCmd shuts down a domain gracefully
func domainStopCmd() *cobra.Command {
	return &cobra.Command{
		Use:     "stop <name>",
		Short:   "Shutdown a domain gracefully",
		Aliases: []string{"shutdown"},
		Args:    cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(cmd)
			if err := apiClient.DomainAction(args[0], "shutdown"); err != nil {
				return fmt.Errorf("failed to stop domain: %w", err)
			}
			fmt.Printf("Domain '%s' shutdown initiated\n", args[0])
			return nil
		},
	}
}

// domainDestroyCmd forcefully stops a domain
func domainDestroyCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "destroy <name>",
		Short: "Forcefully stop a domain",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(cmd)
			if err := apiClient.DomainAction(args[0], "destroy"); err != nil {
				return fmt.Errorf("failed to destroy domain: %w", err)
			}
			fmt.Printf("Domain '%s' destroyed\n", args[0])
			return nil
		},
	}
}

// domainRebootCmd reboots a domain
func domainRebootCmd() *cobra.Command {
	return &cobra.Command{
		Use:   "reboot <name>",
		Short: "Reboot a domain",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(cmd)
			if err := apiClient.DomainAction(args[0], "reboot"); err != nil {
				return fmt.Errorf("failed to reboot domain: %w", err)
			}
			fmt.Printf("Domain '%s' reboot initiated\n", args[0])
			return nil
		},
	}
}

// domainDeleteCmd deletes a domain definition
func domainDeleteCmd() *cobra.Command {
	var force bool

	cmd := &cobra.Command{
		Use:     "delete <name>",
		Short:   "Delete a domain definition",
		Aliases: []string{"rm"},
		Args:    cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			name := args[0]

			if !force {
				fmt.Printf("Are you sure you want to delete domain '%s'? (y/N): ", name)
				var confirm string
				fmt.Scanln(&confirm)
				if confirm != "y" && confirm != "Y" {
					fmt.Println("Cancelled")
					return nil
				}
			} else {
				fmt.Printf("Force deleting domain '%s'...\n", name)
			}
			apiClient := getAPIClient(cmd)

			if err := apiClient.DeleteDomain(name, force); err != nil {
				return fmt.Errorf("failed to delete domain: %w", err)
			}
			fmt.Printf("Domain '%s' deleted\n", name)
			return nil
		},
	}

	cmd.Flags().BoolVarP(&force, "force", "f", false, "Force deletion without confirmation and destroy running domains")
	return cmd
}
